package com.squirrel.common.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.squirrel.common.domain.WebSocketServer;
import com.squirrel.common.entity.UserVideo;
import com.squirrel.common.mapper.UserMapper;
import com.squirrel.common.mapper.UserVideoMapper;
import com.squirrel.common.param.userVideo.EvaluateParam;
import com.squirrel.common.service.UserVideoService;
import com.squirrel.common.util.FileUploadUtils;
import com.squirrel.common.entity.User;
import com.squirrel.common.entity.Video;
import com.squirrel.common.exception.BaseException;
import com.squirrel.common.mapper.VideoMapper;
import com.squirrel.common.param.video.MultipartFileParam;
import com.squirrel.common.param.video.PageParam;
import com.squirrel.common.param.video.VideoParam;
import com.squirrel.common.response.code.CodeEnum;
import com.squirrel.common.response.page.PageResult;
import com.squirrel.common.service.UserService;
import com.squirrel.common.service.VideoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.squirrel.common.util.ImageToolUtils;
import com.squirrel.common.vo.video.VideoInfoVO;
import com.squirrel.common.vo.video.VideoUpVO;
import com.squirrel.common.vo.video.VideoVO;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

/**
 * <p>
 * VideoServiceImp 视频服务实现类
 * </p>
 *
 * @author 关远键
 * @since 2021/11/11 16:06
 */
@Service
public class VideoServiceImp extends ServiceImpl<VideoMapper, Video> implements VideoService {

    @Value("${file.coming.path}")
    private String url;

    @Value("${file.upload.path}")
    private String path;

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserVideoMapper uvMapper;

    @Autowired
    private WebSocketServer wsServer;

    /**
     * 随机获取视频
     * @author 关远键
     * @date 2021/11/14 15:41
     * @return com.squirrel.common.response.page.PageResult<com.squirrel.common.vo.video.VideoVO>
     */
    @Override
    public PageResult<VideoVO> getRandomVideo(int size) {
        Page<VideoVO> page = new Page<>();
        page.setSize(size);
//        page.setCurrent(new Random().nextInt(3) + 1);

        IPage<VideoVO> randomVideo = videoMapper.getRandomVideo(page);

        if (0 == randomVideo.getTotal()) {
            throw new BaseException(CodeEnum.NON_RESOURCE);
        }

        setAndGet(randomVideo);

        return new PageResult<>(randomVideo.getRecords().size(), randomVideo.getRecords());
    }

    /**
     * 根据频道编号获取视频（首页）
     * @author 关远键
     * @date 2021/11/14 15:58
     * @param pageParam 分页
     * @param channelId 频道编号
     * @return com.squirrel.common.response.page.PageResult<com.squirrel.common.vo.video.VideoVO>
     */
    @Override
    public PageResult<VideoVO> getByChannel(PageParam pageParam, Integer channelId) {
        Page<VideoVO> page = new Page<>(pageParam.getNo(), pageParam.getSize());
        IPage<VideoVO> videos = videoMapper.getByChannel(page, channelId);
        if (0 == videos.getTotal()) {
            throw new BaseException(CodeEnum.NON_RESOURCE);
        }
        setAndGet(videos);
        return new PageResult<>(videos.getRecords().size(), videos.getRecords());
    }

    /**
     * 搜索视频
     * @author 关远键
     * @date 2021/11/28 19:10
     * @param pageParam 分页
     * @param key 关键字
     * @return com.squirrel.common.response.page.PageResult<com.squirrel.common.vo.video.VideoVO>
     */
    @Override
    public PageResult<VideoVO> getByKey(PageParam pageParam, String key) {
        Page<VideoVO> page = new Page<>(pageParam.getNo(), pageParam.getSize());

        IPage<VideoVO> listByKey = videoMapper.getByKey(page, key);
        if (0 == listByKey.getTotal()) {
             throw new BaseException(CodeEnum.NON_RESOURCE);
        }

        setAndGet(listByKey);
        return new PageResult<>(listByKey.getRecords().size(), listByKey.getRecords());

    }

    /**
     * 根据频道编号获取视频（点击播放）
     * @author 关远键
     * @date 2021/11/14 16:10
     * @param userId 用户编号
     * @param videoId 视频编号
     * @return com.squirrel.common.vo.video.VideoInfoVO
     */
    @Override
    public VideoInfoVO getById(Integer userId, Integer videoId) {
        VideoInfoVO videoInfoVO = videoMapper.getByVideoId(videoId);
        if (null == videoInfoVO) {
            throw new BaseException(CodeEnum.NON_RESOURCE);
        }

        int online = WebSocketServer.getOnlineCount(videoId).get();
        wsServer.sendAllMessage(videoId, online + "人正在看");

        // 添加观看历史
        if (null != userId) {
            UserVideo uv = uvMapper.get(videoId, userId);
            if (null != uv) {
                uv.setWatched(LocalDateTime.of(LocalDate.now(), LocalTime.now()));
                if (0 == uvMapper.updateById(uv)) {
                    throw new BaseException(CodeEnum.DB_EXCEPTION);
                }
            } else {
                UserVideo userVideo = new UserVideo();
                userVideo.setUserId(userId);
                userVideo.setVideoId(videoId);
                userVideo.setWatched(LocalDateTime.of(LocalDate.now(), LocalTime.now()));
                if (0 == uvMapper.insert(userVideo)) {
                    throw new BaseException(CodeEnum.DB_EXCEPTION);
                }
            }
        }

        // 理应使用redis周期性刷新，等待后期优化
        Video video = videoMapper.selectById(videoInfoVO.getId());
        video.setVideoWatchNumber(video.getVideoWatchNumber() + 1);
        videoMapper.updateById(video);

        videoInfoVO.setAddress(url + videoInfoVO.getAddress());
//        videoInfoVO.setOnline(WebSocketServer.getOnlineCount(videoId).get());

        return videoInfoVO;
    }

    /**
     * 单个视频信息
     * @author 关远键
     * @date 2021/11/23 10:31
     * @param id 视频ID
     * @return com.squirrel.common.vo.video.VideoVO
     */
    @Override
    public VideoVO getByVideoId(Integer id) {
        Video video = videoMapper.selectById(id);

        if (null == video) {
            throw new BaseException(CodeEnum.NON_RESOURCE);
        }

        VideoVO vo = new VideoVO();
        vo.setAuthorId(video.getVideoFrom())
                .setAuthor(userMapper.selectById(video.getVideoFrom()).getNickname())
                .setId(video.getVideoId())
                .setTitle(video.getVideoTitle())
                .setImage(url + video.getVideoImage())
                .setDate(video.getVideoUploadTime())
                .setWatch(video.getVideoWatchNumber());

        return vo;
    }

    /**
     * 查看某个用户发布的视频
     * @author 关远键
     * @date 2021/11/26 15:19
     * @param id 用户ID
     * @return java.util.List<com.squirrel.common.vo.video.VideoVO>
     */
    @Override
    public List<VideoUpVO> getByUserId(Integer id) {
        List<VideoUpVO> list = videoMapper.getByAuthor(id);
        if (null == list) {
            throw new BaseException(CodeEnum.NON_RESOURCE);
        }
        for (VideoUpVO vo: list) {
            vo.setImage(url + vo.getImage());
        }
        return list;
    }

    /**
     * 上传视频
     * @author 关远键
     * @date 2021/11/25 22:17
     * @param fileParam 视频文件
     * @return java.lang.Integer 成功返回视频ID，否则返回分片任务ID
     */
    @Override
    public String upload(MultipartFileParam fileParam) {

        String taskId =  FileUploadUtils.chunkUploadByMappedByteBuffer(fileParam, path);

        if (fileParam.getTotalChunks() != fileParam.getChunkNumber()) {
            System.out.println(taskId + "==========>" + "文件传输未完成");
            return taskId;
        }

        return "文件传输完成";
    }

    /**
     * 文件上传成功时回调
     * @author 关远键
     * @date 2021/11/28 18:46
     * @param videoParam 视频介绍
     * @return java.lang.Integer
     */
    @Override
    public Integer uploadSuccessCallback(VideoParam videoParam) {
        String videoName = videoParam.getNickname() + "-" + videoParam.getFilename();
        String imageName = ImageToolUtils.randomGrabberFFmpegVideoImage(path + "\\" + videoName);
        System.out.println(videoName + "==============>" + imageName);

        Video video = new Video();
        try {
            BeanUtils.copyProperties(video, videoParam);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            throw new BaseException(CodeEnum.FAIL);
        }

        video.setVideoAddress(videoName);
        video.setVideoImage(imageName);
        video.setVideoWatchNumber(0);
        video.setVideoUploadTime(LocalDateTime.of(LocalDate.now(), LocalTime.now()));

        if (0 < videoMapper.insert(video)) {
            return video.getVideoId();
        }

        throw new BaseException(CodeEnum.DB_EXCEPTION);
    }

    /**
     * 格式化：用户ID转用户名
     * @author 关远键
     * @date 2021/11/22 21:41
     * @param video
     */
    private void setAndGet(IPage<VideoVO> video) {
        for (VideoVO vo: video.getRecords()) {
            User user = userMapper.selectById(vo.getAuthorId());
            vo.setAuthor(user.getNickname());
            vo.setImage(url + vo.getImage());
        }
    }

}
